﻿//
// <author>David Nohejl</author>
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WPFTrees.DataStructures;
using WPFTrees.Parser;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using WPFTrees.Tools;
using System.Diagnostics;
using System.Windows.Media;

namespace WPFTrees.Layouts
{
    /// <summary>
    /// Nakresleni stromu ve kterem jsou hrany kolme cary.
    /// </summary>
    public class RectangularLayout:LayoutBase,ISupportGroups,ICanUseBranchLengths
    {
        Canvas _canvas;
        double bottom;
        Point _root;
        double oneChildReservedWidth;
        List<NTreeNode<NewickNode>> _leaves;
        bool useBranchLenghts = true;
        double unit = 0.0; 

        /// <summary>
        /// Vytvori instanci kolmeho layoutu.
        /// </summary>
        public RectangularLayout()
        {            
            _branchDrawer = new RectangularBranchDrawer();
            _isRooted = true;
        }

        /// <inheritdoc />
        public override void ExecuteLayout(Canvas canvas, NTree<NewickNode> tree)
        {
            if (canvas.RenderSize.Width * canvas.RenderSize.Height == 0) return;
            _leaves = tree.Info.Leaves;
            _canvas = canvas;
            _root = new Point(canvas.RenderSize.Width / 2.0, 0);
            Tree = tree;
            bottom = canvas.RenderSize.Height;
            oneChildReservedWidth = canvas.RenderSize.Width / (_leaves.Count - 1);

            unit = canvas.RenderSize.Height /_tree.Info.MaxDepthInUnits;

            ExecuteLayoutRecursive(tree.GetRoot(), _root, 0, canvas.RenderSize.Width);
        }

        /// <summary>
        /// Aktualizuje vizualni prvek znazornujici skupinu.
        /// </summary>
        /// <param name="node">Dany uzel.</param>
        /// <param name="nodePos">Pozice nakresleni uzlu.</param>
        /// <param name="left">Souradnice leveho rohu skupiny.</param>
        /// <param name="width">Sirka skupiny.</param>
        public void UpdateGroupShape(NewickNode node, Point nodePos, 
            double left, double width)
        {
            Rectangle groupRect = node.GroupInfo.Shape as Rectangle;
            Canvas.SetLeft(groupRect,left);
            Canvas.SetTop(groupRect,nodePos.Y);
            groupRect.Width = width;
            groupRect.Height = bottom - nodePos.Y;
        }

        /// <summary>
        /// Traverse tree and recompute canvas coordinates.
        /// </summary>
        /// <param name="root">Root node</param>
        /// <param name="rootPos">position of root node</param>
        /// <param name="left">x-coordinate of reserved space</param>
        /// <param name="right">y=coordinate of reserved space</param>
        void ExecuteLayoutRecursive(NTreeNode<NewickNode> root, Point rootPos,
            double left, double right)
        {
            NewickNode node = root.Value();
            FrameworkElement element = node.VisualElement;

            // position root
            Canvas.SetLeft(element, rootPos.X);
            Canvas.SetTop(element, rootPos.Y);

            Tools.TreeTools.DetermineLabelVisibility(node);

            if (node.IsCollapsed)
            {
                // collapsed root
                return;
            }

            double x = left;
            int count = root.CountImmediateChildren;

            for (int i = 0; i < count; i++)
            {
                NTreeNode<NewickNode> item = root.Children[i];

                if (item == Tree.SelectedNode)
                {
                    Tools.TreeTools.SelectNode(item);
                }

                NewickNode childNode = item.Value();

                if (item.CountImmediateChildren == 0)
                {
                    #region Leaf

                    Tools.TreeTools.DetermineLabelVisibility(childNode);

                    double y;
                    if(useBranchLenghts && childNode.BranchLenght.HasValue)
                        y=rootPos.Y + childNode.BranchLenght.Value * unit;
                    else 
                        y=bottom;
                    Point nodePos = new Point(x, y);
                    // nastavi souradnice listu
                    //childNode.VisualElement.UpdateLayout();
                    Canvas.SetTop(childNode.VisualElement, nodePos.Y);
                    Canvas.SetLeft(childNode.VisualElement, nodePos.X);                    

                    _branchDrawer.PositionBranch(childNode.BranchToParentElement,
                        node, childNode, rootPos, nodePos);

                    // move left by one slot
                    x += oneChildReservedWidth;
                    #endregion

                }
                else
                {
                    #region subtree
                    // compute subtree width
                    double newLeft = x;
                    double newRight = x + (item.Leaves - 1) * oneChildReservedWidth;
                    // posune left o sirku podstromu + jeden slot

                    double newRootX = newLeft + (newRight - newLeft) / 2;
                    
                    x = newRight + oneChildReservedWidth;

                    double oneChildReservedHeight = _canvas.RenderSize.Height/_leaves.Count;

                    double newRootY;
                    if(useBranchLenghts && childNode.BranchLenght.HasValue)
                        newRootY = rootPos.Y + childNode.BranchLenght.Value * unit;
                    else
                        newRootY = bottom - (item.Leaves * oneChildReservedHeight);

                    #region group
                    if (childNode.GroupInfo != null)
                    {                        
                        UpdateGroupShape(childNode, 
                            new Point(newRootX, newRootY),
                            newLeft,newRight-newLeft);                     
                    }
                    #endregion                    

                    Point nodePos = new Point(newRootX, newRootY);

                    _branchDrawer.PositionBranch(childNode.BranchToParentElement,
                        node, childNode, rootPos, nodePos);

                    ExecuteLayoutRecursive(item, nodePos, newLeft, newRight);

                    #endregion
                }
            }
        }
     
        
        /// <inheritdoc />
        public Shape CreateGroupShape(NewickNode node)
        {
            Rectangle rect = new Rectangle();
            rect.Fill = new SolidColorBrush(node.GroupInfo.Color);
            rect.Opacity = 0.5;
            rect.Name = node.Label;            
            return rect;
        }

        /// <inheritdoc />
        public bool UseBranchLenghts
        {
            get
            {
                return useBranchLenghts;
            }
            set
            {
                useBranchLenghts = value;
            }
        }          
    
    }
}
